<script lang="ts">
    import { onDestroy, onMount, untrack } from "svelte";
    import { useClassList } from "../utils/useClassList";
    import useCopy from "../utils/useCopy";
    import { getRandomIntInclusive } from "../utils/utils";
    import type { ParagraphProps } from "./Typography";
    import { getRenderText } from "./utils";
    import { useStyle } from "../utils/useStyle";
    import Link from "./Link.svelte";
    import { Tooltip } from "../Tooltip";
    import type { Action } from "svelte/action";
    import { _ } from "svelte-i18n";
    import IconCopyCheck from "../Common/Icons/IconCopyCheck.svelte";
    import IconCopy from "../Common/Icons/IconCopy.svelte";
    import Icon from "../Common/Icons/Icon.svelte";

    const props: ParagraphProps = $props();

    let copyed = $state(false);
    let expanded = $state(false);

    let realChildrenText = $state("");
    let visibleText = $derived(realChildrenText);
    let tooltipVisible = $state(false);
    let u = $state(getRandomIntInclusive(0, 1000000));
    let ref: HTMLElement | null = null;
    let copyRef: HTMLElement | undefined = $state();
    let expandRef: HTMLElement | null = null;

    const defaultEllipsisConfig = {
        rows: 1,
        expandable: false,
        collapsible: false,
        showTooltip: false,
        expandText: $_("Paragraph.expandText"),
        collapseText: $_("Paragraph.collapseText"),
        suffix: "",
        onExpand: (status: boolean) => {},
    };
    const ellipsisConfig = typeof props.ellipsis === "object" ? Object.assign(defaultEllipsisConfig, props.ellipsis) : defaultEllipsisConfig;

    const canUseCSSEllipsis = $derived.by(() => {
        const { expandable, expandText, suffix } = ellipsisConfig;
        return !expandable && !expandText && !props.copyable && !suffix?.length;
    });

    const classList = $derived(
        useClassList(props, "cm-typograghy-paragraph", {
            [`cm-typograghy-paragraph-${props.size || "normal"}`]: true,
            [`cm-typograghy-paragraph-${props.type}`]: !!props.type,
            "cm-typograghy-extended": props.spacing === "extended",
            "cm-typograghy-ellipsis": !!props.ellipsis && canUseCSSEllipsis,
        }),
    );

    const style = $derived(
        useStyle(props, {
            "-webkit-line-clamp": `${ellipsisConfig.rows}`,
        }),
    );

    async function onCopy() {
        const ret = await useCopy(props.copyText ?? realChildrenText);
        copyed = ret;
        if (ret) {
            props.oncopy?.();
            setTimeout(() => {
                copyed = false;
            }, 4000);
        }
    }

    // 切换展开状态
    function toggleExpand() {
        // 获取新的展开状态
        const newExpanded = !expanded;
        // 设置新的展开状态
        expanded = newExpanded;
        if (newExpanded) {
            visibleText = realChildrenText;
            tooltipVisible = false;
        }
        // 如果有onExpand回调函数，则调用回调函数
        ellipsisConfig.onexpand?.(newExpanded);
    }

    $effect(() => {
        const exped = expanded;
        u;
        if (!props.ellipsis) {
            return;
        }
        untrack(() => {
            if (ref && ellipsisConfig.rows) {
                const useCSSEllipsis = canUseCSSEllipsis;
                if (useCSSEllipsis) {
                    return;
                }
            }
            if (typeof realChildrenText !== "string") {
                console.warn("[CUI Typography] Only children with pure text could be used with ellipsis at this moment.");
            }
            if (!ellipsisConfig.rows || ellipsisConfig.rows < 0 || exped) {
                return;
            }

            if (ref) {
                const extraNode = { expand: expandRef, copy: copyRef };
                const content = getRenderText(ref, ellipsisConfig.rows, realChildrenText, extraNode, "...", ellipsisConfig.suffix);

                visibleText = content;
            }
        });
    });

    onMount(() => {
        const ob = new ResizeObserver(() => {
            u = getRandomIntInclusive(0, 1000000);
        });

        ob.observe(ref as Element);

        onDestroy(() => {
            ob.disconnect();
        });
    });

    const getToolTipOptions = () => {
        if (ellipsisConfig.showTooltip) {
            if (typeof ellipsisConfig.showTooltip === "object") {
                const options: any = { ...(ellipsisConfig.showTooltip as object) };
                if (!options.content) {
                    options.content = realChildrenText;
                }
                return options;
            } else if (typeof ellipsisConfig.showTooltip === "boolean" && ellipsisConfig.showTooltip) {
                return {
                    content: realChildrenText,
                };
            }
        }
    };

    const action: Action = (node) => {
        realChildrenText = node.innerText;
    };
</script>

{#snippet innerContent()}
    <div {style} class={classList} bind:this={ref}>
        <span style="display: none" use:action>{@render props.children?.()}</span>
        <span>{visibleText}</span>{#if props.copyable}{#if copyed}<span class="cm-typograghy-copyed" bind:this={copyRef}>
                    <Icon icon="copycheck"></Icon>
                </span>{:else}<span class="cm-typograghy-copy" bind:this={copyRef} onclick={onCopy}>
                    <Icon icon="copy"></Icon>
                </span>{/if}{/if}<span bind:this={expandRef} class="cm-typograghy-expand">
            {#if ellipsisConfig.expandable && !expanded}
                <Link onclick={toggleExpand}>{ellipsisConfig.expandText}</Link>
            {/if}
            {#if ellipsisConfig.collapsible && expanded}
                <Link onclick={toggleExpand}>{ellipsisConfig.collapseText}</Link>
            {/if}
        </span>
    </div>
{/snippet}

{#if ellipsisConfig.showTooltip}
    <Tooltip {...getToolTipOptions()} bind:visible={tooltipVisible} disabled={expanded}>{@render innerContent()}</Tooltip>
{:else}
    {@render innerContent()}
{/if}
